<template>
  <div class="cascader-select-panel">
    <van-checkbox-group
      :value="value"
      @input="onSelectChange"
    >
      <van-empty v-if="(tabDataList || []).length <= 0" description="暂无数据" />
      <van-tabs v-else class="van-cascader__tabs" :color="color" type="line" :swipe-threshold="1" v-model="activePanel" :style="{height: height}">
        <van-tab v-for="tabData in tabDataList" :key="tabData.id"
          class="tab-content-item"
          :title-class="getTitleClass(tabData)"
        >
          <template #title>
            <span class="tab-item">
              {{ getTabItemTitle(tabData) || '请选择' }}
            </span>
          </template>
          <!-- Tab页内容 -->
          <van-empty v-if="getTabContentList(tabData.index).length <= 0" description="暂无数据" />
          <van-cell v-else
            v-for="data in getTabContentList(tabData.index)" :key="data[finalProps.value]"
            @click="onSelectContentItem(tabData, data)"
            title-style="min-width:60%;"
          >
            <template #title>
              <van-checkbox v-if="finalProps.showCheckbox == null || data[finalProps.showCheckbox]"
                style="width: 100%;"
                shape="square"
                icon-size="16px"
                :color="color"
                :name="data[finalProps.value]"
                :disabled="calcItemDisabled(data)"
                @click.native.stop="() => {}"
              >
                {{ data[finalProps.text] }}
              </van-checkbox>
              <span v-else @click.stop="() => {}">{{ data[finalProps.text] }}</span>
            </template>
            <template #right-icon>
              <van-row class="right-icon" type="flex" v-if="hasChild(data)" justify="end" align="center">
                <van-badge v-if="getChildSelectCount(data)" :content="getChildSelectCount(data)" color="#EF502F" />
                <van-icon name="arrow" />
              </van-row>
            </template>
          </van-cell>
        </van-tab>
      </van-tabs>
    </van-checkbox-group>
  </div>
</template>

<script>
import { findTreeNodeObjectPath } from '@/utils';

const DEFAULT_PROPS = {
  // 显示名称字段
  text: 'name',
  // 值字段
  value: 'id',
  // 子节点数组字段
  children: 'children',
  // 是否禁用字段
  disabled: 'disabled',
  // 是否叶子节点字段 (如果为空则判断子节点是否为空)
  leaf: undefined,
  // 是否允许选择
  showCheckbox: undefined,
  // 完整数据
  data: undefined
}

export default {
  name: 'cascaderSelectPanel',
  props: {
    value: {
      type: Array
    },
    // 是否禁用
    disabled: {
      type: Boolean,
      default: false
    },
    // 选中颜色
    color: {
      type: String
    },
    // 组件高度
    height: {
      type: String
    },
    // 组件数据
    options: {
      type: Array,
      default: () => []
    },
    props: {
      type: Object,
      default: () => {
        return {
          ...DEFAULT_PROPS
        }
      }
    },
    // 选项过滤函数
    filter: {
      type: Function
    }
  },
  data () {
    return {
      activePanel: 0,
      tabDataList: []
    }
  },
  methods: {
    // 计算tab页title class
    getTitleClass (tabData) {
      return `van-cascader__tab${tabData.value == null ? ' van-cascader__tab--unselected' : ''}`;
    },
    // 选项是否禁用
    calcItemDisabled (data) {
      if (this.disabled) return true;
      if (data == null) return false;
      if (typeof this.finalProps.disabled === 'function') {
        return this.finalProps.disabled(data);
      } else {
        return this.finalProps.disabled == null ? false : data[this.finalProps.disabled];
      }
    },
    // 选中项改变
    onSelectChange (val) {
      this.$emit('input', val);
    },
    // 是否包含子节点
    hasChild (data) {
      if (this.finalProps.leaf != null && this.finalProps.leaf !== '') return !data[this.finalProps.leaf];
      return Array.isArray(data[this.finalProps.children]) && data[this.finalProps.children].length > 0;
    },
    // Tab页标题
    getTabItemTitle (tabData) {
      let selectDataList = this.getTabSelectDataList(tabData);
      if (tabData == null || (selectDataList.length <= 0 && tabData.value == null)) return null;
      if (tabData.value != null) return tabData.value[this.finalProps.text];
      return selectDataList.map(item => {
        return item[this.finalProps.text];
      }).join(' / ');
    },
    // 当前Tab页选中数据列表
    getTabSelectDataList (tabData) {
      if (tabData == null) return [];
      let dataList = this.getTabContentList(tabData.index);
      return (dataList || []).filter(item => {
        return (this.value || []).indexOf(item[this.finalProps.value]) !== -1;
      });
    },
    // 点击内容项右侧箭头
    onSelectContentItem (tabData, data) {
      if (!this.hasChild(data)) return;
      let oldIndex = this.activePanel;
      // 设置点击项为当前Tab的选中项
      tabData.value = data;
      let tempTime = new Date().getTime();
      // 移除当前Tab页后面所有的Tab页，并且更新当前tab页id（用于刷新当前tab页面）
      this.tabDataList = this.tabDataList.slice(0, tabData.index + 1).map(item => {
        return {
          ...item,
          id: item.index === this.activePanel ? tempTime++ : item.id
        }
      });
      // 如果包含子节点，那么添加新Tab页
      if (Array.isArray(data[this.finalProps.children]) && data[this.finalProps.children].length > 0) {
        this.tabDataList.push({
          id: tempTime++,
          index: this.tabDataList.length,
          value: undefined
        });
        oldIndex++
      }
      this.$nextTick(() => {
        this.activePanel = oldIndex;
      });
    },
    // 获取Tab页下数据列表
    getTabContentList (index) {
      let parentTab = this.tabDataList[index - 1];
      if (parentTab == null) {
        let tempList = this.options || [];
        return this.pathNodeCount.filter ? tempList.filter(item => {
          return this.pathNodeCount.filter[item[this.finalProps.value]] != null;
        }) : tempList;
      } else {
        if (parentTab.value != null) {
          let tempList = parentTab.value[this.finalProps.children] || [];
          return this.pathNodeCount.filter ? tempList.filter(item => {
            return this.pathNodeCount.filter[item[this.finalProps.value]] != null;
          }) : tempList;
        } else {
          return [];
        }
      }
    },
    // 初始化Tab页面
    initTabPanel () {
      if (Array.isArray(this.options) && this.options.length > 0) {
        this.tabDataList = [
          {
            id: new Date().getTime(),
            index: 0,
            value: undefined
          }
        ];
      } else {
        this.tabDataList = [];
      }
    },
    // 获取当前节点下有多少项被选中
    getChildSelectCount (data) {
      return data ? this.pathNodeCount.count[data[this.finalProps.value]] : undefined;
    },
    getSelectDataList () {
      if (Array.isArray(this.value)) {
        return this.value.map(item => {
          let path = findTreeNodeObjectPath(this.options, item, this.finalProps.value, this.finalProps.children);
          return (Array.isArray(path) && path.length > 0) ? path : null;
        }).filter(item => item != null);
      }
    },
    reset () {
      this.initTabPanel();
    }
  },
  computed: {
    // 根据树形数据以及选中数据计算途经节点命中次数 / 如果有过滤，计算过滤命中的节点以及它的父节点
    pathNodeCount () {
      let temp = {
        count: {},
        filter: typeof this.filter === 'function' ? {} : undefined
      };
      function findTreeNode (node, idSet, path, idKey, childKey, filter, temp) {
        // 计算选中节点数量
        if (idSet.has(node[idKey])) {
          path.forEach(parent => {
            if (temp) {
              if (temp.count[parent[idKey]] == null) {
                temp.count[parent[idKey]] = 0;
              }
              temp.count[parent[idKey]] = temp.count[parent[idKey]] + 1;
            }
          });
        }
        if (Array.isArray(path)) path.push(node);
        // 计算是过滤后的节点（包括命中节点以及它的父节点）
        if (typeof filter === 'function' && filter(node)) {
          path.forEach(parent => {
            if (temp) {
              if (temp.filter == null) {
                temp.filter = {};
              }
              if (temp.filter[parent[idKey]] == null) {
                temp.filter[parent[idKey]] = true;
              }
            }
          });
        }
        if (node[childKey] != null && Array.isArray(node[childKey])) {
          for (let i = 0; i < node[childKey].length; i++) {
            findTreeNode(node[childKey][i], idSet, path, idKey, childKey, filter, temp);
          }
        }
        if (Array.isArray(path)) path.pop();
      }
      if (Array.isArray(this.value) && Array.isArray(this.options)) {
        let path = [];
        let idSet = new Set(this.value);
        this.options.forEach(node => {
          path = [];
          findTreeNode(node, idSet, path, this.finalProps.value, this.finalProps.children, this.filter, temp);
        });
        idSet = null;
      }
      console.log(temp);
      return temp;
    },
    finalProps () {
      return {
        ...DEFAULT_PROPS,
        ...this.props
      }
    }
  },
  watch: {
    value: {
      handler () {
        this.tabDataList.forEach(item => {
          item.id = (item.value == null && item.index === this.activePanel) ? new Date().getTime() : item.id;
        });
      },
      immediate: true
    },
    options: {
      handler () {
        this.reset();
      },
      immediate: true
    }
  }
}
</script>

<style scoped>
  .tab-content-item /deep/ .van-cell__title {
    flex-grow: 0;
    flex-shrink: 0;
    max-width: calc(100% - 50px);
  }
  .tab-content-item .right-icon {
    flex-grow: 1;
    text-align: right;
    line-height: 24px;
    height: 24px;
    font-size: 16px;
    color: #969799;
    margin-left: 4px;
  }
  .cascader-select-panel /deep/ .van-tabs__content {
    padding-top: 15px;
    border-top: 1px solid #F7F7F7;
    height: calc(100% - 64px);
    overflow: auto;
  }
  .cascader-select-panel /deep/ .van-tabs__nav {
    padding-left: 6px!important;
    padding-right: 6px!important;
  }
  .tab-item {
    display: inline-block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 30vw;
    min-width: 40px;
    text-align: center;
  }
</style>
